package GerenciadorDeSom;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

import Main.GamePanel;

public class SoundPlayer {

	@SuppressWarnings("rawtypes")
	ArrayList soundBank;
	public boolean mute;
	

	@SuppressWarnings("rawtypes")
	public SoundPlayer() {
		soundBank = new ArrayList();
		mute = false;
	}

	@SuppressWarnings("unchecked")
	public void addtrack(String fnm, int ntracks, boolean looping) {
		ControladorDeSom tc = new ControladorDeSom(this, fnm, ntracks, looping);
		soundBank.add(tc);
	}

	public int getNumTracks(){
		return soundBank.size();
	}

	public void playTrack(int itrack,float volume,float balance) {
		if (mute)
			return;
		((ControladorDeSom) soundBank.get(itrack)).Play(volume,balance);
	}
	
	public void playTrack(int itrack) {
		if (mute) {
			return;
		}
		((ControladorDeSom) soundBank.get(itrack)).Play();
	}
	
	public void Stop() {
		for (int i = 0; i < soundBank.size(); i++) {
			((ControladorDeSom) soundBank.get(i)).Stop();
		}
	}
	
	public void Stop(int indice) {
		((ControladorDeSom) soundBank.get(indice)).Stop();
	}
}

class ControladorDeSom implements LineListener {
	boolean forcedstop = false;
	ArrayList<Clip> listofclips;
	boolean looping = false;
	int ntracks;
	SoundPlayer soundplayer = null;

	public ControladorDeSom(SoundPlayer soundplayer, String fnm, int nclips, boolean looping) {
		this.soundplayer = soundplayer;
		this.looping = looping;
		listofclips = new ArrayList<Clip>();
		ntracks = nclips;
		for (int i = 0; i < nclips; i++) {
			addtrack(fnm);
		}
	}

	public void addtrack(String fnm) {
		AudioInputStream stream;
		//File file = new File(fnm);
		InputStream is = GamePanel.instance.getClass().getResourceAsStream("/"+fnm);
		try {
			stream = AudioSystem.getAudioInputStream(is);
			AudioFormat format = stream.getFormat();
			if ((format.getEncoding() == AudioFormat.Encoding.ULAW)
					|| (format.getEncoding() == AudioFormat.Encoding.ALAW)) {
				AudioFormat newFormat = new AudioFormat(
						AudioFormat.Encoding.PCM_SIGNED,
						format.getSampleRate(),
						format.getSampleSizeInBits() * 2, format.getChannels(),
						format.getFrameSize() * 2, format.getFrameRate(), true);
				stream = AudioSystem.getAudioInputStream(newFormat, stream);
				format = newFormat;
			}
			DataLine.Info info = new DataLine.Info(Clip.class, format);
			if (!AudioSystem.isLineSupported(info)) {
				System.exit(0);
			}
			Clip clip = null;
			try {
				clip = (Clip) AudioSystem.getLine(info);
				clip.addLineListener(this);
				clip.open(stream);
			} catch (IOException e) {
				e.printStackTrace();
			} catch (LineUnavailableException e) {
				e.printStackTrace();
			}
			listofclips.add(clip);
		} catch (UnsupportedAudioFileException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void Play(float volume,float balance){
		int nframes = 0;
		for (int i = 0; i < listofclips.size(); i++) {
			Clip clip = (Clip) listofclips.get(i);
			nframes = clip.getFrameLength();
			if ((clip != null) && (clip.isRunning() == false)) {
				clip.stop();
				clip.setFramePosition(0);
				if( clip.isControlSupported(FloatControl.Type.MASTER_GAIN)){
					FloatControl m_gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
					m_gainControl.setValue(volume);
				}
				if(clip.isControlSupported(FloatControl.Type.BALANCE)){
					((FloatControl)clip.getControl(FloatControl.Type.BALANCE)).setValue(balance);
				}
				clip.start();
				forcedstop = false;
				return;
			}
		}
		int minframe = (nframes * 3) / 4;
		for (int i = 0; i < listofclips.size(); i++) {
			Clip clip = (Clip) listofclips.get(i);
			if (clip.getFramePosition() > minframe) {
				if( clip.isControlSupported(FloatControl.Type.MASTER_GAIN)){
					FloatControl m_gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
					m_gainControl.setValue(volume);
				}
				if(clip.isControlSupported(FloatControl.Type.BALANCE)){
					((FloatControl)clip.getControl(FloatControl.Type.BALANCE)).setValue(balance);
				}
				clip.setFramePosition(0);
				forcedstop = false;
				return;
			}
		}
	}
	
	public void Play() {
		int nframes = 0;
		for (int i = 0; i < listofclips.size(); i++) {
			Clip clip = (Clip) listofclips.get(i);
			nframes = clip.getFrameLength();
			if ((clip != null) && (clip.isRunning() == false)) {
				clip.stop();
				clip.setFramePosition(0);
				clip.start();
				forcedstop = false;
				return;
			}
		}
		int minframe = (nframes * 3) / 4;
		for (int i = 0; i < listofclips.size(); i++) {
			Clip clip = (Clip) listofclips.get(i);
			if (clip.getFramePosition() > minframe) {
				clip.setFramePosition(0);
				forcedstop = false;
				return;
			}
		}
	}

	public void Stop() {
		forcedstop = true;
		for (int i = 0; i < listofclips.size(); i++) {
			Clip clip = (Clip) listofclips.get(i);
			clip.stop();
		}
	}

	public void update(LineEvent event) {
		if (looping && (event.getType() == LineEvent.Type.STOP)) {
			if (!soundplayer.mute && !forcedstop) {
				Play();
			}
		}
	}
}
